﻿using AiMoBridge.Interface;
using AiMoCore;
using AiMoRhino.Preview;
using Rhino;
using Rhino.Commands;
using System;
using System.Diagnostics;

namespace AiMoRhino.Main
{
    class RhinoExecutor : IExecutor
    {
        string runCommandError = "";
        string runCommandTime = "";
        readonly Previewer previewer;
        CompiledAssemblyInfo CurrentAssembly { get; set; }
        public RhinoExecutor()
        {
            previewer = new Previewer();
        }
        public string RunCommandError => runCommandError;
        public string RunCommandTime => runCommandTime;
        public bool RunSriptCommand(IExecutorInfo executorInfo)
        {
            runCommandError = "";
            runCommandTime = "";
            if (Command.InCommand())
            {
                runCommandError = Local.Get("Cannot run scripts while other command is running");
                return false;
            }
            // 执行一个空的assembly将会清空之前的Load，待测试
            if (string.IsNullOrEmpty(executorInfo.AssemblyPath))
            {
                CurrentAssembly?.Dispose();
                return true;
            }
            if (CurrentAssembly == null || CurrentAssembly.Path != executorInfo.AssemblyPath)
            {
                CurrentAssembly?.Dispose();
                bool re = CompiledAssemblyInfo.TryGetCompiledAssemblyInfo(executorInfo.AssemblyPath, executorInfo.ExternalAssembliesPaths, out CompiledAssemblyInfo loadedAssembly, out string error);
                if (!re)
                {
                    runCommandError = $"{Local.Get("Cannot load assembly at")} {executorInfo.AssemblyPath}, " + error;
                    return false;
                }
                else
                {
                    runCommandError = error;
                }
                loadedAssembly.ScriptInstance.SetPrinter(executorInfo.Printer);
                loadedAssembly.ScriptInstance.SetPreviewer(previewer);
                CurrentAssembly = loadedAssembly;
            }
            Stopwatch timer = Stopwatch.StartNew();
            Result result = Result.Failure;
            RhinoApp.InvokeAndWait(new Action(() => { result = RhinoApp.ExecuteCommand(RhinoDoc.ActiveDoc, CSharpScriptCommand.Instance.EnglishName); }));
            timer.Stop();
            runCommandTime = string.Format(Local.Get("Scripts run in {0:f3} sec"), timer.Elapsed.TotalSeconds);
            return result == Result.Success;
        }
        /// <summary>
        /// 通过上一个RunSriptCommand函数，调用Rhino命令，命令内运行这个函数
        /// </summary>
        public bool RunCommand()
        {
            if (CurrentAssembly == null) return false;
            try
            {
                CSharpScriptInstance instance = CurrentAssembly.ScriptInstance;
                instance.LoopOff();
                previewer.Clear();
                previewer.EnableDraw();
                instance.BeforeMain();
                instance.Main();
                if (previewer.IsEmpty && (!instance.OnLoop))
                {
                    previewer.ClosePreview();
                }
                RhinoDoc.ActiveDoc.Views.Redraw();
                return true;
            }
            catch (Exception ex)
            {
                runCommandError = $"{Local.Get("RunCommand Exception:")}\r\n   {ex.Message}\r\n{ex.StackTrace} ";
                return false;
                //StackTrace stackTrace = new StackTrace(ex, true);
                //StackFrame frame = stackTrace.GetFrame(0);
                //int lineNumber = frame.GetFileLineNumber();
                //int columnNumber = frame.GetFileColumnNumber();
                //runCommandError = $"{Local.Get("RunCommand Exception:")}   [Ln:{lineNumber}, Col:{columnNumber}]\r\n   {ex.Message}\r\n{ex.StackTrace} ";
                //return false;
            }
        }
    }
}
